package br.com.edumobi.dados;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import br.com.edumobi.P;
import br.com.edumobi.T;
import br.com.edumobi.dados.modelos.Alternativa;
import br.com.edumobi.dados.modelos.Aluno;
import br.com.edumobi.dados.modelos.Cidade;
import br.com.edumobi.dados.modelos.Classificacao;
import br.com.edumobi.dados.modelos.Endereco;
import br.com.edumobi.dados.modelos.Questao;
import br.com.edumobi.dados.modelos.Simulado;
import br.com.edumobi.dados.modelos.enuns.Nivel;
import br.com.edumobi.dados.modelos.enuns.Sexo;
import br.com.edumobi.dados.modelos.enuns.UF;
import br.com.edumobi.excecoes.ExcecaoAtualizacaoDadosAlunoMalsucedida;
import br.com.edumobi.excecoes.ExcecaoAutenticacaoMalsucedida;
import br.com.edumobi.excecoes.ExcecaoCadastroAlunoMalsucedido;
import br.com.edumobi.excecoes.ExcecaoConsultaMalsucedida;
import br.com.edumobi.excecoes.ExcecaoRegerarSenhaAlunoMalsucedido;
import br.com.edumobi.utils.Dates;

public class DadosNuvem implements IDadosNuvem {

    private static final String SERVER = "37.187.123.154:8080/edumobi/services/";

    private InputStream readJSON(String url) throws IOException, RuntimeException {
        HttpURLConnection conexao = (HttpURLConnection) new URL(url).openConnection();

        conexao.setReadTimeout(10 * 1000);
        conexao.setConnectTimeout(10 * 1000);
        conexao.setDoInput(true);
        conexao.setRequestMethod("GET");

        conexao.connect();

        if (conexao.getResponseCode() == HttpURLConnection.HTTP_OK){
            return conexao.getInputStream();
        } else {
            return null;
        }
    }

    private String inputStreamToString(InputStream inputStream) throws IOException {
        if (inputStream != null) {
            byte[] buffer = new byte[1024];
            int bytesLidos;
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            while ((bytesLidos = inputStream.read(buffer)) > -1){
                byteArrayOutputStream.write(buffer, 0, bytesLidos);
            }
            return new String(byteArrayOutputStream.toByteArray());
        } else {
            return null;
        }
    }

    @Override
    public Aluno autenticarAluno(String email, String senha) throws ExcecaoAutenticacaoMalsucedida {
        if (P.EM_TESTE && T.MOCK_USUARIO_VALIDO_EMAIL.equals(email) && T.MOCK_USUARIO_VALIDO_SENHA.equals(senha)) {
            return T.getMockAlunoValido();
        } else {
            StringBuilder url = new StringBuilder()
                    .append("http://")
                    .append(SERVER)
                    .append("validarLogin.do?email=")
                    .append(email)
                    .append("&senha=")
                    .append(senha);

            try {
                String retorno = inputStreamToString(readJSON(url.toString()));

                if (retorno == null || retorno.isEmpty()) {
                    throw new ExcecaoAutenticacaoMalsucedida();
                } else {
                    JSONObject jsonAluno = new JSONObject(retorno);

                    Aluno aluno;

                    Long id = jsonAluno.getLong("id");
                    String nome = jsonAluno.getString("nome");
                    String cpf = jsonAluno.getString("cpf");
                    String matricula = jsonAluno.getString("matricula");
                    Sexo sexo = Sexo.getEnum(jsonAluno.getString("sexo"));
                    Date dataNascimento = Dates.stringParaDate(jsonAluno.getString("dataNascimento"), Dates.FORMATO_YYYY_MM_DD);

                    String logradouro = jsonAluno.getString("logradouro");
                    String numero = jsonAluno.getString("numero");
                    String complemento = jsonAluno.getString("complemento");
                    String bairro = jsonAluno.getString("bairro");
                    String cep = jsonAluno.getString("cep");

                    Cidade cidade = null;

                    if (!jsonAluno.isNull("municipio")) {
                        JSONObject jsonCidade = jsonAluno.getJSONObject("municipio");

                        cidade = new Cidade(
                                jsonCidade.getLong("id"),
                                jsonCidade.getString("nome"),
                                UF.getEnum(jsonCidade.getJSONObject("uf").getInt("id")));
                    }

                    Endereco endereco = new Endereco(logradouro, numero, complemento, bairro, cep, cidade);

                    String telefoneResidencial = jsonAluno.getString("telefoneResidencial");
                    String telefoneCelular = jsonAluno.getString("celular");

                    aluno = new Aluno(
                            id,
                            nome,
                            cpf,
                            email,
                            senha,
                            sexo,
                            matricula,
                            dataNascimento,
                            endereco,
                            telefoneResidencial,
                            telefoneCelular);

                    return aluno;
                }
            } catch (Exception excecao) {
                throw new ExcecaoAutenticacaoMalsucedida();
            }
        }
    }

    @Override
    public void cadastrarAluno(String nome, String email, String cpf) throws ExcecaoCadastroAlunoMalsucedido {
        StringBuilder url = new StringBuilder()
                .append("http://")
                .append(SERVER);

        try {
            String retorno = inputStreamToString(readJSON(url.toString()));

            if (retorno == null || retorno.isEmpty()) {
                throw new ExcecaoCadastroAlunoMalsucedido();
            }

        } catch (Exception excecao) {
            throw new ExcecaoCadastroAlunoMalsucedido();
        }
    }

    @Override
    public void regerarSenhaAluno(String email) throws ExcecaoRegerarSenhaAlunoMalsucedido {
        StringBuilder url = new StringBuilder()
              .append("http://")
              .append(SERVER)
              .append("regerarSenha.do?email=")
              .append(email);

        try {
            String retorno = inputStreamToString(readJSON(url.toString()));

            if (retorno == null || retorno.isEmpty()) {
                throw new ExcecaoAutenticacaoMalsucedida();
            }

        } catch (Exception excecao) {
            throw new ExcecaoRegerarSenhaAlunoMalsucedido();
        }
    }

    @Override
    public void salvarDadosAluno(Aluno aluno) throws ExcecaoAtualizacaoDadosAlunoMalsucedida {
        StringBuilder url = new StringBuilder()
                .append("http://")
                .append(SERVER);

        try {
            String retorno = inputStreamToString(readJSON(url.toString()));

            if (retorno == null || retorno.isEmpty()) {
                throw new ExcecaoCadastroAlunoMalsucedido();
            }

        } catch (Exception excecao) {
            throw new ExcecaoAtualizacaoDadosAlunoMalsucedida();
        }
    }

    @Override
    public List<Classificacao> consultarClassificacoesDoAluno(Aluno aluno) throws ExcecaoConsultaMalsucedida {
        if (P.EM_TESTE && T.MOCK_USUARIO_VALIDO_EMAIL.equals(aluno.email) && T.MOCK_USUARIO_VALIDO_SENHA.equals(aluno.senha)) {
            return T.getMockListaDeClassificacoes();
        } else {
            StringBuilder url = new StringBuilder()
                    .append("http://")
                    .append(SERVER)
                    .append("validarLogin.do?email=")
                    .append(aluno.email)
                    .append("&senha=")
                    .append(aluno.senha);

            try {
                String retorno = inputStreamToString(readJSON(url.toString()));

                if (retorno == null || retorno.isEmpty()) {
                    throw new ExcecaoConsultaMalsucedida();
                } else {
                    JSONArray jsonClassicicacoes = new JSONObject(retorno).getJSONArray("cursos");

                    List<Classificacao> classificacoes = new ArrayList<Classificacao>();

                    int qtdRegistro = jsonClassicicacoes.length();

                    for (int index = 0; index < qtdRegistro; index++) {
                        JSONObject jsonClassificacao = jsonClassicicacoes.getJSONObject(index);

                        classificacoes.add(jsonObjectParaClassificacao(jsonClassificacao));
                    }

                    return classificacoes;
                }

            } catch (Exception excecao) {
                throw new ExcecaoConsultaMalsucedida();
            }
        }
    }

    private Classificacao jsonObjectParaClassificacao(JSONObject jsonObject) throws IOException, JSONException {
        Classificacao classificacao = new Classificacao();

        classificacao.id = jsonObject.getLong("id");
        classificacao.nome = jsonObject.getString("nome");
        classificacao.descricao = jsonObject.getString("descricao");

        classificacao.classificacaoSuperior = jsonObject.isNull("pai") ? null : jsonObjectParaClassificacao(jsonObject.getJSONObject("pai"));

        classificacao.questoes = consultarQuestoesPorClassificacao(classificacao);

        return classificacao;
    }

    private List<Questao> consultarQuestoesPorClassificacao(Classificacao classificacao) throws IOException, JSONException {
        StringBuilder url = new StringBuilder()
                .append("http://")
                .append(SERVER)
                .append("questoes.do?idCategoria=")
                .append(classificacao.id);

        String retorno = inputStreamToString(readJSON(url.toString()));

        JSONArray jsonQuestoes = new JSONArray(retorno);

        List<Questao> questoes = new ArrayList<Questao>();

        int qtdRegistros = jsonQuestoes.length();

        for (int index = 0; index < qtdRegistros; index++) {
            questoes.add(jsonObjectParaQuestao(jsonQuestoes.getJSONObject(index)));
        }

        return questoes;
    }

    private Questao jsonObjectParaQuestao(JSONObject jsonObject) throws IOException, JSONException {
        Questao questao = new Questao();

        questao.id = jsonObject.getLong("id");
        questao.enunciado = jsonObject.getString("enunciado");
        questao.observacao = jsonObject.getString("observacao");
        questao.alternativas = jsonArrayParaAlternativas(jsonObject.getJSONArray("listaAlternativasDTO"));
        questao.alternativaCorreta = jsonObjectParaAlternativaCorreta(jsonObject.getJSONArray("listaAlternativasDTO"));
        questao.nivel = Nivel.MEDIO;

        return questao;
    }

    private List<Alternativa> jsonArrayParaAlternativas(JSONArray jsonArray) throws IOException, JSONException {
        int qtdRegistros = jsonArray.length();
        List<Alternativa> alternativas = new ArrayList<Alternativa>();

        for (int index = 0; index < qtdRegistros; index++) {
            alternativas.add(jsonObjectParaAlternativa(jsonArray.getJSONObject(index)));
        }

        return alternativas;
    }

    private Alternativa jsonObjectParaAlternativa(JSONObject jsonObject) throws IOException, JSONException {
        Alternativa alternativa = new Alternativa();

        alternativa.id = jsonObject.getLong("id");
        alternativa.alternativa = jsonObject.getString("resposta");

        return alternativa;
    }

    private Alternativa jsonObjectParaAlternativaCorreta(JSONArray jsonArray) throws IOException, JSONException {
        int qtdRegistros = jsonArray.length();

        Alternativa alternativaCorreta = null;

        for (int index = 0; index < qtdRegistros; index++) {
            if (jsonArray.getJSONObject(index).getBoolean("correta")) {
                alternativaCorreta = jsonObjectParaAlternativa(jsonArray.getJSONObject(index));
            }
        }

        return alternativaCorreta;
    }

    @Override
    public List<Simulado> consultarSimulados(Classificacao classificacao, Aluno aluno) throws ExcecaoConsultaMalsucedida {
        if (P.EM_TESTE && T.MOCK_USUARIO_VALIDO_EMAIL.equals(aluno.email) && T.MOCK_USUARIO_VALIDO_SENHA.equals(aluno.senha)) {
            return T.getMockListaDeSimulados();
        } else {
            StringBuilder url = new StringBuilder()
                    .append("http://")
                    .append(SERVER)
                    .append("simulados.do?idCategoria=")
                    .append(classificacao.id);

            try {
                String retorno = inputStreamToString(readJSON(url.toString()));

                if (retorno == null || retorno.isEmpty()) {
                    throw new ExcecaoConsultaMalsucedida();
                } else {
                    List<Simulado> simulados = new ArrayList<Simulado>();

                    JSONArray jsonArray = new JSONArray(retorno);

                    int qtdRegistros = jsonArray.length();

                    for (int index = 0; index < qtdRegistros; index++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(index);

                        Simulado simulado = new Simulado();

                        simulado.id = jsonObject.getLong("id");
                        simulado.titulo = jsonObject.getString("titulo");
                        simulado.descricao = jsonObject.getString("descricao");
                        simulado.duracao = new Date(Long.valueOf(String.valueOf(jsonObject.getLong("duracao")).substring(1)));
                        simulado.quantidadeDeQuestoes = jsonObject.getInt("qtdQuestao");
                        simulado.classificacao = classificacao;

                        simulados.add(simulado);
                    }

                    return simulados;
                }

            } catch (Exception excecao) {
                throw new ExcecaoConsultaMalsucedida();
            }
        }
    }

    @Override
    public List<Questao> consultarQuestoesDoSimulado(Simulado simulado, Aluno aluno) throws ExcecaoConsultaMalsucedida {
        if (P.EM_TESTE && T.MOCK_USUARIO_VALIDO_EMAIL.equals(aluno.email) && T.MOCK_USUARIO_VALIDO_SENHA.equals(aluno.senha)) {
            return T.getMockListaDeQuestoesSimulado();
        } else {
            StringBuilder url = new StringBuilder()
                    .append("http://")
                    .append(SERVER)
                    .append("questoesSimulado.do?idSimulado=")
                    .append(simulado.id);

            try {
                String retorno = inputStreamToString(readJSON(url.toString()));

                if (retorno == null || retorno.isEmpty()) {
                    throw new ExcecaoConsultaMalsucedida();
                } else {
                    JSONArray jsonArray = new JSONArray(retorno);

                    List<Questao> questoes = new ArrayList<Questao>();

                    int qtdRegistros = jsonArray.length();

                    for (int index = 0; index < qtdRegistros; index++) {
                        questoes.add(jsonObjectParaQuestao(jsonArray.getJSONObject(index)));
                    }

                    return questoes;
                }

            } catch (Exception excecao) {
                throw new ExcecaoConsultaMalsucedida();
            }
        }
    }
}